//	This document define the cache api.
dojo.provide("spaghetti.cache");

dojo.require("spaghetti.utility");

dojo.declare("spaghetti.cache.CacheItem", null, {
	//	summary:
	//		All the object put into the cache will be wrapped by an item. This item is the basic cache 
	//		item. It has the last used time and priority to supports to support the LRU and Priority 
	//		cache algorithm. Other cache implementation can use its cache item. For example, the refreshable
	//		cache can use its cache item to track the object's state(stale | fresh).
	
	//	obj: Object
	//		The object reference this cache holded.
	obj : null,
	
	//	begin: Long
	//		The time stamp for this item construct.
	begin : null,
	
	//	priority: Integer[0-4]
	//		The priority for this item. priority 4 > priority 0
	priority : 0,
	
	//	last: Long
	//		The last time get this item's object.
	last : null,
	
	constructor : function(/*Object*/ obj, /*Object*/ keywordArgs){
		//	summary:
		//		The constructor for cache item.
		//	
		//	obj: Object
		//		The object this item to hold.
		//
		//	keywordArgs: Object
		//		The configration for this item. 
		//	example: 
		//	|	{ priority : 4 }
		
		this.obj = obj;
		
		if(!spaghetti.isNull(keywordArgs))
			dojo.mixin(this, keywordArgs);
			
		// Set the construct time.
		this.begin = new Date().getTime();
	},
	
	beforeGetObject : function(){
		//	summary:
		//		The hook event for get object from this item. If the subclass persist the cached object,
		//		can use this method to retrieve it.
	},
	
	afterGetObject : function(/*Object*/ obj){
		//	summary:
		//		The hook event for get object from this item.
	},
	
	getObject : function(){
		this.beforeGetObject();
		var obj = this.obj;
		// Track the last used time.
		this.last = new Date().getTime();
		this.afterGetObject(obj);
		return obj;
	},
	
	destroy : function(){
		//	summary:
		//		This method will be called, when the cache want to remove the obj. Let the item clean up.
	}
});

dojo.declare("spaghetti.cache.ExpireableItem", spaghetti.cache.CacheItem, {
	//	summary:
	//		The cache item support the cache's expire strategy. If the item expired, it will not be removed,
	//		it should be removed when purge the cache.
	
	constructor : function(/*Object*/ obj, /*Object*/ keywordArgs){
		// If has the expire time. Set the timeout.
		if(!spaghetti.isNull(this.expire))
			spaghetti.setTimeOut(this, "onExpiration", this.expire, [this]);
	},
	
	onExpiration : function(item){
		//	summary:
		//		The event method for this item.
		
		// Set the expired property of this item to true. If the cache purge. This item will be removed.
		this.expired = true;
	}
});

dojo.declare("spaghetti.cache.api", null, {
	//	summary:
	//		The api for cache, this api is the guide for the cache implementation. And a interface for
	//		the datasource. It defines the basic cache strategy all the implemetation must provide. 
	
	setLimit : function(/*Integer*/ limit){
		//	summary:
		//		Set the limit of this cache. The limit is the object count.	If the objects number in the
		//		cache reach the limit, the cache will be purged to spare the room for the new object. If
		//		the purge can not provide a room, the cache will use a strategy to remove an object for
		//		spare the room for the new object.
		//
		//	limit: Number
		//		The limit of this cache.
		
		spaghetti.notImplement("setLimit");
	},
	
	/*Integer*/ getLimit : function(){
		//	summary:
		//		Return the limit of this cache.
		
		spaghetti.notImplement("getLimit");
	},
	
	/*Integet*/ getSize : function(){
		//	summary:
		//		Return the size of the current cache.
		
		spaghetti.notImplement("getSize");
	},
	
	/*String[]*/ getKeys : function(){
		//	return:
		//		All the keys in this cache.
		
		spaghetti.notImplement("getKeys");
	},
	
	/*String[]*/ getFeatures : function(){
		//	summary:
		//		Get the cache features this cache support.
		//
		//	LRU: 
		//		The cache support the least recent used strategy.
		//
		//	Priority:
		//		The caceh support the priority strategy. When need remove one object, remove the least important one.
		//
		//	Refreshable:
		//		Item can be fresh in a set time. When time out, the item is staled. If the item has a refresh method.
		//		It will refresh itself when get the object from it, else it will throw an exception.
		//
		//	Exprieable:
		//		Can set the item exprie time. If expried, it will be removed from the cache. If not set, suppose it
		//		will not expire.
		
		return ["LRU", "Priority", "Expireable"];
	},
	
	/*Boolean*/ put : function(/*String*/ key, /*Object*/ obj, /*Object*/ strategy){
		//	summary:
		//		Put the object into the cache with a key. Use the keywordArgs to config.
		//
		//	key: String
		//		The key for find the object in the cache.
		//
		//	obj: Object
		//		The object to put into cache.
		//
		//	strategy: Object
		//		The stategy for the cache item. It can varies by the implementation for the cache. Mostly the cache can
		//		leave the task to the cache item and this is the configration for the cache item. LRU need not configration,
		//		but the Priority, Refreshable and Expireable need configration, for example 
		//			*priority*, the priority for the obj. 
		//			*expire*, the expire time count.
		//			*fresh*, the fresh time count. When time out, the object is stale.
		//
		//	return: Boolean
		//		If the put operation is successed, return true, else return false.
		
		spaghetti.notImplement("put");
	},
	
	get : function(/*String*/ key){
		//	summary:
		//		Get the object from the cache by the key.
		
		spaghetti.notImplement("get");
	},
	
	remove : function(/*String*/ key){
		//	summary:
		//		Remove the object from the cache forever by the key.
		
		spaghetti.notImplement("remove");
	},
	
	/*Integer*/ purge : function(){
		//	summary:
		//		Purge the cache manually. 
		//
		//	return: Integer
		//		How many object is remove in this purge.
		
		spaghetti.notImplement("purge");
	},
	
	clear : function(){
		//	summary:
		//		Remove everything from the cache.
		
		spaghetti.notImplement("clear");
	}
});